package cn.com.git.example.config.security;


import cn.com.git.example.common.auth.AuthConstant;
import cn.com.git.example.common.auth.AuthenticationTokenDTO;
import cn.com.git.example.common.auth.LoginStatusDTO;
import cn.com.git.example.common.constant.LoginStateEnum;
import cn.com.git.example.common.util.object.JSONUtils;
import cn.com.git.example.common.util.security.JwtUtils;
import cn.com.git.example.module.service.AuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 授权过滤器
 *
 * @author Administrator
 */
public class AuthenticationFilter extends BasicAuthenticationFilter {

    @Value("${spring.profiles.active}")
    private String profile;

    @Value("${auth.jwt.token.key}")
    private String jwtKey;

    @Autowired
    private LoginContext loginContext;

    @Autowired
    private AuthenticationService authenticationService;


    public AuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        //判断是否触发主动鉴权
        if (filterNeedRequest(request)) {
            UsernamePasswordAuthenticationToken authentication = getAuthenticationProxy(request);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        }
        chain.doFilter(request, response);
    }

    /**
     * 过滤需要主动鉴权的请求
     *
     * @param request
     * @return
     */
    public boolean filterNeedRequest(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        logger.debug("method=setLoginContext,params[url = [" + request.getRequestURL() + "]" + ",token = [" + token + "]" + "]");
        //登出 不鉴权
        if ("/sso/logout".equals(request.getRequestURI())) {
            return false;
        }
        //无 token 不鉴权
        if (token == null) {
            return false;
        }
        return true;
    }

    /**
     * 通过环境判断鉴权方式
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthenticationProxy(HttpServletRequest request){
        String token = request.getHeader("Authorization");
        //判断是否mock
        boolean mock = token.startsWith("test") && !"pro".equals(profile);
        if(mock){
            return getMockAuthentication(request);
        }
        return getAuthentication(request);
    }
    /**
     * 获取鉴权信息
     * mock 的登录用户，用于便捷开发
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getMockAuthentication(HttpServletRequest request) {
        AuthenticationTokenDTO authenticationDTO = this.setLoginContext(AuthConstant.testToken, request);
        return new UsernamePasswordAuthenticationToken(authenticationDTO.getSysUser().getAccount(), null, null);
    }
    /**
     * 获取鉴权信息
     * 正式环境使用
     * @param request
     * @return
     */
    private UsernamePasswordAuthenticationToken getAuthentication(HttpServletRequest request) {
        String token = request.getHeader("Authorization");
        AuthenticationTokenDTO authenticationTokenDTO = this.parseToken(token);
        if (authenticationTokenDTO == null) {
            return null;
        }
        LoginStatusDTO loginStatus = authenticationService.getLoginStatus(authenticationTokenDTO.getSysUser().getAccount());
        if (loginStatus == null) {
            return null;
        }
        if (!LoginStateEnum.UPLOAD_STATE_2.getValue().equals(loginStatus.getLoginState())) {
            return null;
        }
        AuthenticationTokenDTO authenticationDTO = this.setLoginContext(authenticationTokenDTO, request);
        return new UsernamePasswordAuthenticationToken(authenticationDTO.getSysUser().getAccount(), null, null);
    }

    /**
     * 解析 token,返回对象
     *
     * @param token
     * @return
     */
    private AuthenticationTokenDTO parseToken(String token) {
        JwtUtils.TokenEntity entity = JwtUtils.parseToken(token, jwtKey);
        if (entity == null) {
            return null;
        }
        AuthenticationTokenDTO authenticationTokenDTO = JSONUtils.fromJson(entity.getSubject(), AuthenticationTokenDTO.class);
        return authenticationTokenDTO;
    }

    /**
     * 保存访问用户
     *
     * @param authenticationTokenDTO
     * @param request
     * @return
     */
    AuthenticationTokenDTO setLoginContext(AuthenticationTokenDTO authenticationTokenDTO, HttpServletRequest request) {
        loginContext.setCurrentUser(authenticationTokenDTO);
        return authenticationTokenDTO;
    }
}
